﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  GetPinSequence.cs
//    
// Abstract:
//
// SequenceActivity for verifying a user's PIN for reminders.
//  
//--

using System;
using System.Diagnostics;
using System.Globalization;
using System.Workflow.Activities;
using Microsoft.OfficeCommunicationsServer.Applications.Common;
using Microsoft.Rtc.Workflow.Activities;
using Microsoft.Speech.Synthesis;
using Microsoft.Speech.Recognition;

namespace Microsoft.EnhancedReminders.Dispatcher.Workflow
{
    /// <summary>
    /// SequenceActivity for verifying a user's PIN for reminders.
    /// </summary>
    public sealed partial class GetPinSequence : CommunicationsSequenceActivity
	{
        /// <summary>
        /// The maximum number of attempts a user gets at entering a PIN.
        /// </summary>
        private readonly int _maximumAttempts = 3;

        /// <summary>
        /// Flag to mark whether the pin we got from the caller was correct.
        /// </summary>
        private bool _pinCorrect;

        /// <summary>
        /// Number of times we've encountered an invalid PIN in this call.
        /// </summary>
        private int _numIncorrectEntires;

        private NotificationItem _notification;

        /// <summary>
        /// ctor.
        /// </summary>
        public GetPinSequence()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Returns the base path to the Dispatcher assemblies.
        /// </summary>
        public string BasePath
        {
            get
            {
                return System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location) + "\\";
            }
        }

        /// <summary>
        /// The NotificationItem being delivered in this call.
        /// </summary>
        public NotificationItem Notification
        {
            get { return _notification; }
            set { _notification = value; }
        }

        #region Code Conditions
        private void IfRecognition(object sender, ConditionalEventArgs e)
        {
            e.Result = "StarStar".Equals(askPin.RecognitionResult.Semantics.Value);
        }

        private void IsPinCorrect(object sender, ConditionalEventArgs e)
        {
            e.Result = _pinCorrect;
        }

        private void IsPinIncorrect(object sender, ConditionalEventArgs e)
        {
            _numIncorrectEntires++;
            e.Result = !_pinCorrect && _numIncorrectEntires < _maximumAttempts;
        }
        #endregion Code Conditions

        private void PerformPinValidation(object sender, EventArgs e)
        {
            // NOTE: Pass the results of the PIN lookup to some secure method for validation. For now
            // we're just looking for the pin "1234".
            _pinCorrect = "1234".Equals(askPin.RecognitionResult.Semantics.Value.ToString());
        }

        private void AskPinTurnStarting(object sender, SpeechTurnStartingEventArgs e)
        {
            Debug.Assert(Notification != null, "Notification != null");

            if (askPin.DtmfGrammars.Count == 0)
            {
                askPin.MainPrompt.ClearContent();
                askPin.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_MainPrompt_1); // "Hi. This is the Enhanced Reminders Service"

                if (Notification.IsJoinNow)
                {
                    string leadTime = DispatcherHelpers.GetLeadTime(CultureInfo.CurrentUICulture, TimeZoneInfo.Local, (Notification as CalendarNotificationItem).StartTime, new SsmlTimeSpanFormatter());

                    askPin.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_MainPrompt_JoinNow_1); // "You have a Live Meeting
                    askPin.MainPrompt.AppendSsmlMarkup(leadTime);
                    askPin.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_MainPrompt_JoinNow_2); // "To join this meeting, or to hear more about it, enter your PIN now."

                    askPin.Prompts.HelpPrompt.AppendAudio(BasePath + PromptAudio.AskPin_HelpPrompt_JoinNow_1); // "This is an automated notification call for"
                    askPin.Prompts.HelpPrompt.AppendText(Notification.DisplayName);
                    askPin.Prompts.HelpPrompt.AppendAudio(BasePath + PromptAudio.AskPin_HelpPrompt_JoinNow_2); // "To join this conference, enter your PIN now."

                    askPin.Prompts.EscalatedSilencePrompt.AppendAudio(BasePath + PromptAudio.AskPin_EscalatedSilencePrompt_JoinNow_1); // "To join this LiveMeeting, please enter your PIN now."
                }
                else
                {
                    if (Notification is VoicemailNotificationItem)
                    {
                        askPin.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_MainPrompt_Voicemail); // "I have a voicemail notification for
                    }
                    else if (Notification is MeetingNotificationItem)
                    {
                        askPin.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_MainPrompt_Meeting); // "I have a meeting notification for
                    }
                    else
                    {
                        Debug.Assert(Notification is CalendarNotificationItem, "Notification is CalendarNotificationItem");
                        askPin.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_MainPrompt_Appointment); // "I have a appointment notification for
                    }

                    askPin.MainPrompt.AppendText(Notification.DisplayName);
                    askPin.MainPrompt.AppendBreak(TimeSpan.FromSeconds(1.0));
                    askPin.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_MainPrompt_NotJoinNow_2); // "Please enter your PIN to hear your reminder."

                    askPin.Prompts.HelpPrompt.AppendAudio(BasePath + PromptAudio.AskPin_HelpPrompt_1); // "This is an automated notification call for"
                    askPin.Prompts.HelpPrompt.AppendText(Notification.DisplayName);
                    askPin.Prompts.HelpPrompt.AppendAudio(BasePath + PromptAudio.AskPin_HelpPrompt_2); // "If that’s you, please say or enter your PIN to hear your notification."

                    askPin.Prompts.EscalatedSilencePrompt.AppendAudio(BasePath + PromptAudio.AskPin_EscalatedSilencePrompt); // "To hear your notification, please enter your PIN."
                }

                askPin.Prompts.RepeatPrompt.AppendPromptBuilder(askPin.MainPrompt);

                askPin.Prompts.NoRecognitionPrompt.AppendAudio(BasePath + PromptAudio.AskPin_NoRecognitionPrompt); // "I didn't get that. What's your PIN?"

                askPin.Prompts.EscalatedNoRecognitionPrompt.AppendAudio(BasePath + PromptAudio.AskPin_EscalatedNoRecognitionPrompt); // "Sorry, I didn't get that etiher. Please say or enter your PIN.

                askPin.Prompts.SilencePrompt.AppendAudio(BasePath + PromptAudio.AskPin_SilencePrompt_1); // "Please enter your PIN now"
                askPin.Prompts.SilencePrompt.AppendAudio(BasePath + PromptAudio.AskPin_SilencePrompt_2); // "If this is the wrong number you can enter the star key twice or simply hang up."

                // set grammars
                askPin.DtmfGrammars.Add(new Grammar(BasePath + Helpers.GetSetting<string>("DtmfGrammar",null),
                    "Pin"));
                askPin.Grammars.Add(new Grammar(BasePath + Helpers.GetSetting<string>("VoiceGrammar",null), "voicepin"));
                askPinHelp.Grammar = new Grammar(BasePath + Helpers.GetSetting<string>("VoiceGrammar",null), "PinHelp");
                askPinRepeat.Grammar = new Grammar(BasePath + Helpers.GetSetting<string>("VoiceGrammar",null), "PinRepeat");
                askPinRepeat.DtmfGrammar = new Grammar(BasePath + Helpers.GetSetting<string>("DtmfGrammar", null), "PinRepeat");
            }
        }

        private void AskPinFinalSilenceTurnStarting(object sender, SpeechTurnStartingEventArgs e)
        {
            Logger.WriteTraceInformation(Notification.Context, "Workflow: Ending call; consecutive silences even hit");
            askPinFinalSilence.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_GoodbyeSilence); // "Thanks for using Enhanced Reminders. Goodbye."
        }

        private void AskPinFinalNoRecoTurnStarting(object sender, SpeechTurnStartingEventArgs e)
        {
            Logger.WriteTraceInformation(Notification.Context, "Workflow: Ending call; consecutive no recognitions even hit");
            askPinFinalNoReco.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_GoodbyeNoReco); // "I’m sorry, but I’m having trouble understanding you.  Please check Outlook for your notification.  Goodbye."
        }

        private void StarStarTurnStarting(object sender, SpeechTurnStartingEventArgs e)
        {
            // This event needs to be logged to a database for the admin to respond to.
            Logger.WriteTraceInformation(Notification.Context, "Workflow: User has pressed **. Do not deliver future calls to {0}", CallProvider.Call.RemoteEndpoint.Participant.PhoneUri);
            starStar.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_GoodbyeSilence); // "I’m sorry to have bothered you.  I’ve noted that this is a wrong number.  Thank you.  Goodbye. "
        }

        private void FailedPinTurnStarting(object sender, SpeechTurnStartingEventArgs e)
        {
            Logger.WriteTraceInformation(Notification.Context, "Workflow: Ending call; user has entered an incorrect PIN three times.");
            failedPin.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_InvalidPinPrompt_3); // "Sorry, but that’s not right.  Please check Outlook for your notification"
        }

        /// <summary>
        /// When a user enters an invalid PIN, we need to re-set the main prompt of the primary
        /// QA to inform the user that they entered the wrong PIN.
        /// </summary>
        /// <param name="sender">Not used.</param>
        /// <param name="e">Not used.</param>
        private void SetPinInvalid(object sender, EventArgs e)
        {
            Logger.WriteTraceInformation(Notification.Context, "Workflow: User has entered an invalid pin.");

            if (_numIncorrectEntires == 1)
            {
                askPin.MainPrompt.ClearContent(); // clear the Main Prompt so that we don't repeat it.
                askPin.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_InvalidPinPrompt_1); // "That PIN doesn’t match.  Please try again."
            }
            else if (_numIncorrectEntires == 2)
            {
                askPin.MainPrompt.ClearContent();
                askPin.MainPrompt.AppendAudio(BasePath + PromptAudio.AskPin_InvalidPinPrompt_2); // "That doesn’t match either.  If this is the wrong number, you can enter the star key twice or simply hang up.  Please try one last time."
            }
        }
	}
}
